package org.ldx.lotterysystem.service.impl;

import cn.hutool.crypto.digest.DigestUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.ldx.lotterysystem.common.errorcode.ServiceErrorCodeConstants;
import org.ldx.lotterysystem.common.exception.ServiceException;
import org.ldx.lotterysystem.common.utils.JWTUtil;
import org.ldx.lotterysystem.common.utils.JacksonUtil;
import org.ldx.lotterysystem.common.utils.RegexUtil;
import org.ldx.lotterysystem.controller.param.MessageLoginParam;
import org.ldx.lotterysystem.controller.param.UserLoginParam;
import org.ldx.lotterysystem.controller.param.UserPasswordLoginParam;
import org.ldx.lotterysystem.controller.param.UserRegisterParam;
import org.ldx.lotterysystem.dao.dataobject.Encrypt;
import org.ldx.lotterysystem.dao.dataobject.UserDo;
import org.ldx.lotterysystem.dao.mapper.UserMapper;
import org.ldx.lotterysystem.service.UserService;
import org.ldx.lotterysystem.service.VerificationCodeService;
import org.ldx.lotterysystem.service.dto.UserDto;
import org.ldx.lotterysystem.service.dto.UserLoginDto;
import org.ldx.lotterysystem.service.dto.UserRegisterDTO;
import org.ldx.lotterysystem.service.enums.UserIdentityEnum;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class UserServiceImpl implements UserService {
    @Resource
    private UserMapper userMapper;
    @Resource
    private VerificationCodeService verificationCodeService;
    @Override
    public UserRegisterDTO register(UserRegisterParam param) {
        //1.校验参数
        checkParam(param);

        //2.加密隐私信息
        UserDo userDo = new UserDo();
        //BeanUtils.copyProperties(param,userDo);
        userDo.setUserName(param.getName());
        userDo.setIdentity(param.getIdentity());
        userDo.setEmail(param.getMail());
        userDo.setPassword(DigestUtil.sha256Hex(param.getPassword()));
        userDo.setPhoneNumber(new Encrypt(param.getPhoneNumber()));
        //3.存储
        userMapper.insert(userDo);
        //4.构造返回值
        UserRegisterDTO dto = new UserRegisterDTO();
        dto.setUserId(userDo.getId());
        return dto;
    }

    @Override
    public UserLoginDto login(UserLoginParam param) {
        UserLoginDto userLoginDto;
        //判断参数类型以知到用户是以何种方式登录的。一行代码解决类型判断与参数转换。JAVA14
        if(param instanceof UserPasswordLoginParam loginParam){
            System.out.println("开始进行密码登录");
            userLoginDto = loginByUserPassword(loginParam);

        }else if (param instanceof MessageLoginParam loginParam) {
            System.out.println("开始进行验证码登录");
            userLoginDto = loginByMessage(loginParam);
        }else {
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_ERROR);
        }
        return userLoginDto;
    }

    @Override
    public List<UserDto> findUserInfoList(UserIdentityEnum userIdentityEnum) {
        String userIdentity = null == userIdentityEnum ? null : userIdentityEnum.name();
        //查表
        List<UserDo> userDos = userMapper.selectUsrListByIdentity(userIdentity);
        //将userDo向UserDto进行转换。。。。。。。
        List<UserDto> userDtos = userDos.stream()
                .map(userDo -> {
            UserDto userDto = new UserDto();
            userDto.setUserName(userDo.getUserName());
            userDto.setIdentity(UserIdentityEnum.forName(userDo.getIdentity()));
            userDto.setEmail(userDo.getEmail());
            userDto.setPhoneNumber(userDo.getPhoneNumber().getPhoneNumber());
            userDto.setUserId(userDo.getId());
            return userDto;
        }).collect(Collectors.toList());
        return userDtos;
    }

    /**
     * 验证码登录
     * @param loginParam
     * @return
     */
    private UserLoginDto loginByMessage(MessageLoginParam loginParam) {
        if(!RegexUtil.checkMail(loginParam.getLoginMobile())){

            throw new ServiceException(ServiceErrorCodeConstants.MAIL_ERROR);
        }
        //根据邮箱号获取用户信息
       UserDo userDo = userMapper.selectByMail(loginParam.getLoginMobile());
        log.info("获取用户信息为：{}", JacksonUtil.writeValueAsString(userDo));
        if(null == userDo){
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EMPTY);
        } else if (StringUtils.hasText(loginParam.getMandatoryIdentity())
        && !loginParam.getMandatoryIdentity().equalsIgnoreCase(userDo.getIdentity())) {
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }
        //校验验证码
        String code = verificationCodeService.getVerificationCode(loginParam.getLoginMobile());
        if(!loginParam.getVerificationCode().equals(code)){
            throw new  ServiceException(ServiceErrorCodeConstants.VERIFICATION_CODE_ERROR);
        }
        //构造返回值
        //JWT
        Map<String,Object> claim = new HashMap<>();
        claim.put("id",userDo.getId());
        claim.put("identity",userDo.getIdentity());
        String token = JWTUtil.genJwt(claim);

        UserLoginDto userLoginDto = new UserLoginDto();
        userLoginDto.setIdentity(UserIdentityEnum.forName(userDo.getIdentity()));
        userLoginDto.setToken(token);

        return userLoginDto;
    }

    /**
     * 密码登录
     * @param loginParam
     * @return
     */
    private UserLoginDto loginByUserPassword(UserPasswordLoginParam loginParam) {
        UserDo userDo = null;
        //判断手机登录还是邮箱登录
        if(RegexUtil.checkMobile(loginParam.getLoginName())){
            //根据手机号查询用户信息
            userDo = userMapper.selectByPhoneNumber(new Encrypt(loginParam.getLoginName()));

        } else if (RegexUtil.checkMail(loginParam.getLoginName())) {
            //根据邮箱号查询用户信息
            userDo = userMapper.selectByMail(loginParam.getLoginName());
        }else {
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_NOT_EXIT);
        }
        //校验登录信息
        if(null == userDo){
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EMPTY);
        } else if (StringUtils.hasText(loginParam.getMandatoryIdentity())
        && !loginParam.getMandatoryIdentity().equalsIgnoreCase(userDo.getIdentity())) {
            //校验身份
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        } else if (!DigestUtil.sha256Hex(loginParam.getPassword()).equals(userDo.getPassword())) {
            //校验密码 加密后判断
            System.out.println("xiixxixixi");
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }
        //构造返回值
        //JWT
        Map<String,Object> claim = new HashMap<>();
        claim.put("id",userDo.getId());
        claim.put("identity",userDo.getIdentity());
        String token = JWTUtil.genJwt(claim);

        UserLoginDto userLoginDto = new UserLoginDto();
        userLoginDto.setIdentity(UserIdentityEnum.forName(userDo.getIdentity()));
        userLoginDto.setToken(token);
        System.out.println("用户为"+userLoginDto.getToken()+userLoginDto.getIdentity());
        return userLoginDto;
    }

    private void checkParam(UserRegisterParam param) {
        if(param == null){
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_ERROR);
        }
        //校验邮箱格式
        if(!RegexUtil.checkMail(param.getMail())){
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_ERROR);
        }
        //校验电话号码格式
        if(!RegexUtil.checkMobile(param.getPhoneNumber())){
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_ERROR);
        }
        //检验身份信息
        if(UserIdentityEnum.forName(param.getIdentity())==null){
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }
        //校验密码是否为必填项
        if(UserIdentityEnum.ADMIN.getMessage().equals(param.getIdentity())
           &&!StringUtils.hasText(param.getPassword())){
            throw new ServiceException(ServiceErrorCodeConstants.NO_PASSWORD);
        }
        //校验密码格式
        if(StringUtils.hasText(param.getPassword())&&!RegexUtil.checkPassword(param.getPassword())){
            System.out.println("hahahahahhah");
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }
        //校验邮箱是否被使用
        if(!checkMailUsed(param.getMail())){
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_USED_ERROR);
        }

        //校验电话号码是否被使用
        if(!checkPhoneNumberUsed(param.getPhoneNumber())){
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_USED_ERROR);
        }

    }

    private boolean checkPhoneNumberUsed(String phoneNumber) {
        return userMapper.countByPhone(new Encrypt(phoneNumber))==0;
    }

    private boolean checkMailUsed(String mail) {
        return userMapper.countByMail(mail)==0;
    }
}
